#include "llvm/Support/JSON.h"
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>

namespace wafer{

class Chip {
public:
    // Constructor
    Chip(const llvm::json::Object &jsonObj) {
        auto value_group = jsonObj.get("group");
        auto value_type = jsonObj.get("type");
        auto value_duty_ratio = jsonObj.get("duty_ratio");

        if (value_group) {
            if (auto strVal = value_group->getAsString()) {
                group = std::stoul(strVal->str());
            } else if (auto numVal = value_group->getAsInteger()) {
                group = static_cast<unsigned long>(numVal.value());
            } else {
                std::cerr << "error: group is neither a string nor a number\n";
            }
        }
        
        // example:"CPU_D2000"
        if (value_type) {
            if (auto strVal = value_type->getAsString()) {
                std::string typeStr = strVal->str();
                // find first'_'
                size_t pos = typeStr.find('_');
                if (pos != std::string::npos) {
                    // intercept
                    type = typeStr.substr(0, pos);
                } else {
                    std::cerr << "error: Format mismatch!\n";
                }
            }
        }

        if (value_duty_ratio) {
            if (auto strVal = value_duty_ratio->getAsString()) {
                duty_ratio = std::stof(strVal->str());
            } else if (auto numVal = value_duty_ratio->getAsNumber()) {
                duty_ratio = static_cast<float>(numVal.value());
            } else {
                std::cerr << "error: duty_ratio is neither a string nor a number\n";
            }
        }
    }

    const size_t getGroup() const{
        return group;
    }

    const std::string& getType() const{
        return type;
    }

    const float getDutyRatio() const{
        return duty_ratio;
    }

private:
    size_t group;
    std::string type;
    float duty_ratio;
};

class Chips {
public:
    // Constructor
    Chips(const llvm::json::Object &jsonObj) {
        if (auto chipArray = jsonObj.getArray("Chip")) {
            for (const auto &item : *chipArray) {
                if (const llvm::json::Object *chipObj = item.getAsObject()) {
                    chip.push_back(Chip(*chipObj));
                }
            }
        }
    }

    const std::vector<Chip> getChipArray() const{
        return chip;
    }

    std::size_t CPUNum(){
        std::size_t count = 0;
        for(auto i : chip){
            if(i.getType() == "CPU") count++;
        }
        return count;
    }

    bool HasGPU(){
        for(auto i : chip){
            if(i.getType() == "GPU") return true;
        }
        return false;
    }


private:
    std::vector<Chip> chip;
};



class Architecture {
public:
    // Constructor
    Architecture(const llvm::json::Object &jsonObj) {
        chips = new Chips(*(jsonObj.getObject("Chiplets")));
    }

    Chips getChips(){
        return *chips;
    }

private:
    Chips* chips;
};

// Root class representing the entire JSON structure
class Root {
public:
    // 禁止拷贝构造和赋值
    Root(const Root&) = delete;
    Root& operator=(const Root&) = delete;

    // 提供一个静态方法来获取实例
    static Root& getInstance() {
        static Root instance;
        return instance;
    }

    void initialize(const std::string &filePath) {
        std::ifstream fileStream(filePath);
        if (!fileStream) {
            llvm::errs() << "Failed to open file: " << filePath << "\n";
            return;
        }
        std::stringstream buffer;
        buffer << fileStream.rdbuf();
        std::string str = buffer.str();

        llvm::Expected<llvm::json::Value> json = llvm::json::parse(str);

        if (!json) {
            llvm::errs() << "JSON parsing failed\n";
            return;
        }

        llvm::json::Object* jsonObj = json->getAsObject();

        if (jsonObj) {
            architecture = new Architecture(*(jsonObj->getObject("Architecture")));
            
        }
        initialized = true;
    }

    Architecture getArchitecture() const{
        return *architecture;
    }
    bool isInitialized() { return initialized; }
    ~Root(){delete architecture;};

private:
    Root() {
        // 构造函数中不进行初始化
    }
    bool initialized = false;
    Architecture* architecture;
};

}